
class Bitmap
{
public:
    Bitmap();
    Bitmap(const Bitmap &B);
    Bitmap(Bitmap &&B);
    Bitmap(UINT Width, UINT Height);
    Bitmap(UINT Width, UINT Height, RGBColor clearColor);

    ~Bitmap();

    //
    // Memory
    //
    void FreeMemory();
    void Allocate(UINT Width, UINT Height);
    void Allocate(UINT Width, UINT Height, RGBColor clearColor);
    void operator = (const Bitmap &Bmp);
    void operator = (Bitmap &&Bmp);

    //
    // Accessors
    //
    inline RGBColor* operator [] (UINT Row) {return &_data[Row * _width];}
    inline const RGBColor* operator [] (UINT Row) const {return &_data[Row * _width];}
    inline RGBColor* Pixels() {return _data;}
    inline const RGBColor* Pixels() const {return _data;}
    inline UINT Width() const {return _width;}
    inline UINT Height() const {return _height;}
    inline UINT PixelCount() const {return _width * _height;}
    inline Vec2i Dimensions() const {return Vec2i(_width, _height);}
    
    //
    // File Functions
    //
    void SavePNG(const string &filename) const;
    void LoadPNG(const string &filename);

    static Bitmap LoadFile(const string &filename);
    
    //
    // Transfer Functions
    //
    void BltTo(Bitmap &B, int TargetX, int TargetY) const;
    void TransparentBltTo(Bitmap &B, int TargetX, int TargetY) const;
    void BltTo(Bitmap &B, int TargetX, int TargetY, int SourceX, int SourceY, int Width, int Height) const;
    
    void FlipHorizontal();
    void FlipVertical();
    
    //
    // Query
    //
    UINT Hash32() const;
    UINT64 Hash64() const;
    bool PerfectMatch(const Bitmap &Bmp) const;
    UINT CountPixelsWithColor(RGBColor Color) const;
    
    inline bool ValidCoordinates(int x, int y) const
    {
        return (x >= 0 && x < int(_width) && y >= 0 && y < int(_height));
    }

    //
    // Modifiers
    //
    void Clear(const RGBColor &Color);    //clears all pixels to Color
    void Clear();                         //clears all pixels to RGBColor::Black
    void FlipBlueAndRed();
    
private:
    static void __cdecl PNGReadFromBuffer(png_structp png_ptr, png_bytep data, png_size_t length);
    static void __cdecl PNGWriteToBuffer(png_structp png_ptr, png_bytep data, png_size_t length);
    static void __cdecl PNGFlushBuffer(png_structp png_ptr);
    void PNGCompleteRead(png_structp PngRead, png_infop PngInfo, const string &filename);
    void PNGCompleteWrite(png_structp PngWrite, png_infop PngInfo) const;

    UINT _width, _height;
    RGBColor* _data;
};

OutputDataStream& operator << (OutputDataStream &stream, const Bitmap &bmp);
InputDataStream& operator >> (InputDataStream &stream, Bitmap &bmp);
